using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace DuplexTransformers
{
    public class Transformer<TLeft, TRight> : ITransformer<TLeft, TRight>
    {
        private static readonly string RelationshipMethodName;
        private readonly List<object> _relationships = new List<object>();

        static Transformer()
        {
            Expression<Action<PropertyRelationship<int, string, object, object>>> expr = x => x.SetDestinationPropertyFromTransformedSourceProperty(1, default(string));
            var methodCallExpression = (MethodCallExpression) expr.Body;
            RelationshipMethodName = methodCallExpression.Method.Name;
        }

        public TRight Invoke(TLeft left, TRight right)
        {
            var types = new[] {typeof (TLeft), typeof (TRight)};
            var parameters = new object[] {left, right};
            foreach (var relationship in _relationships)
            {
                var method = relationship.GetType().GetMethod(RelationshipMethodName, types);
                method.Invoke(relationship, parameters);
            }
            return right;
        }

        public TLeft Invoke(TRight right, TLeft left)
        {
            var types = new[] {right.GetType(), left.GetType()};
            var parameters = new object[] {right, left};
            foreach (var relationship in _relationships)
            {
                var method = relationship.GetType().GetMethod(RelationshipMethodName, types);
                method.Invoke(relationship, parameters);
            }
            return left;
        }

        public LeftExpression<TLeft, TRight, TProp> Property<TProp>(Expression<Func<TLeft, TProp>> expr)
        {
            var result = new LeftExpression<TLeft, TRight, TProp>(this, expr);
            return result;
        }

        public LeftListExpression<TLeft, TRight, TPropItem> Property<TPropItem>(Expression<Func<TLeft, IList<TPropItem>>> expr)
        {
            var result = new LeftListExpression<TLeft, TRight, TPropItem>(this, expr);
            return result;
        }

        public void AddRelationship<TLeftProp, TRightProp>(PropertyRelationship<TLeft, TRight, TLeftProp, TRightProp> propertyRelationship)
        {
            AddRelationshipInternal(propertyRelationship);
        }

        public void AddRelationshipInternal(object propertyRelationship)
        {
            _relationships.Add(propertyRelationship);
        }
    }
}